package rlyy.framework.netty.inithandler;

import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import rlyy.framework.netty.inithandler.strategy.IRequestProcess;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * @author yuanqinglong
 * @since 2020/6/3 14:10
 */
@ChannelHandler.Sharable
@Component
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    static final Logger logger = LoggerFactory.getLogger(HttpServerHandler.class);
    public static final SerializeConfig SERIALIZE_CONFIG = new SerializeConfig();

    static {
        SERIALIZE_CONFIG.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
    }

    /**
     * 所有定义的请求处理器
     */
    @Autowired
    private List<IRequestProcess> iRequestProcessors;

    /**
     * maxConnections
     */
    private int maxConnections = 10000;

    private final AtomicInteger connections = new AtomicInteger();


    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if(connections.incrementAndGet() < maxConnections) {
            super.channelActive(ctx);
        } else{
            ctx.close();
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        connections.decrementAndGet();
    }




    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
        long startTime = System.currentTimeMillis();
        logger.info(" Request Method :{} ", request.method());
        try {
            for (IRequestProcess iRequestProcessor : iRequestProcessors) {
                if (iRequestProcessor.supportsHandler(request)) {
                    iRequestProcessor.requestHandler(ctx, request);
                    logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
                    //请求结束 清除此线程的请求上下文 释放ThreadLocal
                    MDC.clear();
                    return;
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
            logger.error("has an error: ", exception);
            writeResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR));
            return;
        } finally {
            RequestContextHolder.resetRequestAttributes();
        }
        // 没有处理器支持处理此请求 返回错误提示
        logger.warn("Request method '{}' not supported", request.method());
        writeResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.METHOD_NOT_ALLOWED));
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.fireExceptionCaught(cause);
    }


    public static void writeResponse(ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse response) {
        boolean keepAlive = HttpUtil.isKeepAlive(request);
        HttpUtil.setKeepAlive(request, keepAlive);
        ctx.writeAndFlush(response);
    }



}
